#ifndef AST_HPP
#define AST_HPP

#include "tokens.hpp"

#include <vector>
#include <list>
#include <string>
#include <memory>

namespace
{
	template< class ContainerT >
	void deleteContents( ContainerT& container )
	{
		for( typename ContainerT::iterator i = container.begin(); i != container.end(); ++i )
		{
			delete (*i);
		}
	}
}

struct ASTNode
{
	virtual ~ASTNode() {};
	typedef std::auto_ptr<ASTNode> aptr;
};

struct TypeAST : public ASTNode
{
	typedef std::auto_ptr<TypeAST> aptr;
};

struct StatementAST : public ASTNode
{
	typedef std::auto_ptr<StatementAST> aptr;
	// donolol
};

struct CallAST : public ASTNode
{
	typedef std::auto_ptr<CallAST> aptr;
	
	~CallAST()
	{
		deleteContents(parameters);
	}
	
	ASTNode::aptr object;
	std::vector<ASTNode*> parameters;
};

struct MemberAccessAST : public ASTNode
{
	typedef std::auto_ptr<MemberAccessAST> aptr;
	ASTNode::aptr object;
	ASTNode::aptr memberName;
};

struct VariableDeclarationAST : public ASTNode
{
	typedef std::auto_ptr<VariableDeclarationAST> aptr;
	std::string name;
	ASTNode::aptr type;
	ASTNode::aptr initialization;
};

struct WhileAST : public ASTNode
{
	typedef std::auto_ptr<WhileAST> aptr;
	ASTNode::aptr condition;
	ASTNode::aptr body;
};

struct DoWhileAST : public ASTNode
{
	typedef std::auto_ptr<DoWhileAST> aptr;
	ASTNode::aptr condition;
	ASTNode::aptr body;
};

struct IfAST : public ASTNode
{
	typedef std::auto_ptr<IfAST> aptr;
	ASTNode::aptr condition;
	ASTNode::aptr body1;
	ASTNode::aptr body2;
};

struct TemplateSpecializationAST : public ASTNode
{
	typedef std::auto_ptr<TemplateSpecializationAST> aptr;
	
	~TemplateSpecializationAST()
	{
		deleteContents(parameters);
	}
	
	std::string name;
	std::vector<ASTNode*> parameters;
};

struct ValueAST : public ASTNode
{
	typedef std::auto_ptr<ValueAST> aptr;
};

struct IdentifierAST : public ASTNode
{
	typedef std::auto_ptr<IdentifierAST> aptr;
	
	IdentifierAST( const std::string& name_) : name(name_) {}
	
	std::string name;
};

struct BinOpAST : public ASTNode
{
	typedef std::auto_ptr<BinOpAST> aptr;
};

struct UnaryOpAST : public ASTNode
{
	typedef std::auto_ptr<UnaryOpAST> aptr;

	Tkn::Token op;
	ASTNode::aptr argument;
};

struct CodeBlockAST : public ASTNode
{
	typedef std::auto_ptr<CodeBlockAST> aptr;
	
	~CodeBlockAST()
	{
		deleteContents( statements );
	}
	
	std::list<ASTNode*> statements;
};

struct FunctionAST : public ASTNode
{
	typedef std::auto_ptr<FunctionAST> aptr;
	
	struct Parameter
	{
		std::string name;
		ASTNode::aptr type;
		ASTNode::aptr defaultValue;
	};
	
	~FunctionAST()
	{
		deleteContents( parameters );
	}
	
	std::string name;
	std::vector<Parameter*> parameters;
	ASTNode::aptr type;
	ASTNode::aptr body;
};

struct ClassAST : public ASTNode
{
	typedef std::auto_ptr<ClassAST> aptr;
	std::string name;
	// ETC
};

struct ModuleAST : public ASTNode
{
	typedef std::auto_ptr<ModuleAST> aptr;
	//std::list<sth> imports
	//std::list<sth> exports
	ModuleAST() {};
	
	~ModuleAST() {
		deleteContents( functions );
		deleteContents( classes );
	}
	
	std::list<ASTNode*> functions;
	std::list<ASTNode*> classes;
};

#endif //AST_HPP
